//Copyright 2012 Trevin Liberty
//GNU GPL v3
//Author: Trevin Liberty
//
//Base Class of all Entities

#ifndef ENTITY_H
#define ENTITY_H

#include "../Structs.h"
#include "Doohickey.h"
#include "Pathing\AStar.h"
#include "Pathing\AStarStructs.h"

#include <cassert>

//SEE: Top of file
class Entity : public Doohickey {
private:
protected:
	AStar* aStar;

	short unsigned int strength;
	short unsigned int agility;
	short unsigned int experience;
	short unsigned int level;
	short unsigned int attackSpeed; //in ms

	float speed;
	float attackRange;

	Doohickey* target;
	float lastAttackTime;

	list<Point<int>> *currentPath;
	Point<int> currentDestination;
	Point<int> goal;
	float blockedTime;
	float firstBlockedTime;
	bool arrived;

	enum Direction {N, S, E, W, NE, NW, SE, SW};
	Direction prevDir;
	Direction direction;

	bool shouldUpdatePath();

public:
	//Constructor
	//	PARAMS:
	//int maxHealth, Map* map, Point<int> imageBound: SEE: Doohickey.h
	//AStar* aStar: A pointer to a new aStar.
	//ATTN: ALL Entities should point to the SAME aStar.
	//
	//AStar* aStar may be NULL, IFF, setAStar(...) is called before using the Entity.
	Entity(int maxHealth, Map* map, Point<int> imageBound, AStar* aStar) 
		: Doohickey(maxHealth, map, imageBound),
		  experience(0), 
		  level(0),
		  target(NULL),
		  aStar(aStar),
		  lastAttackTime(0),
		  goal(Point<int>(-1, -1)),
		  blockedTime(-1),
		  firstBlockedTime(-1),
		  direction(E),
		  prevDir(E),
		  arrived(true) {}

	//Used to initialize the Entity
	//	PARAMS:
	//short int strength, short int agility, float attackSpeed, float speed,
	//	float attackRange: Entity Stats
	void initEntity(short int strength, short int agility, float attackSpeed, float speed,
		float attackRange);

	//Accessors
	short unsigned int getStrength() const {return strength;}
	short unsigned int getAgility() const {return agility;}
	short unsigned int getAttackSpeed() const {return attackSpeed;}
	short unsigned int getExperience() const {return experience;}
	short unsigned int getLevel() const {return level;}
	float getSpeed() const {return speed;}
	float getAttackRange() const {return attackRange;}

	//Mutators
	void addToStrength(int t) {strength += t;}
	void addToAgility(int t) {agility += t;}
	void addToAttackSpeed(int t) {attackSpeed += t;}
	void addToExperience(int t) {experience += t;}
	void addToLevel(int t) {level += t;}
	void addToSpeed(float t) {speed += t;}
	void addToAttackRange(float t) {attackRange += t;}

	//Returns the Entity current target.
	//If no target, returns NULL.
	Doohickey* getTarget() const {return target;}

	//Return true if Entity has a target
	bool hasTarget() const {return target != NULL;}

	//Sets the Entity's target
	//	PARAMS:
	//Doohickey* d: Pointer to the Entity's new target.
	void setTarget(Doohickey* d) {target = d;}

	//Removes the target.
	void removeTarget() {target = NULL;}

	//Returns the time of the Entity's last attack
	float getLastAttackTime() const {return lastAttackTime;}

	//Set the time of the Entity's last attack to NOW
	void setLastAttackTime() {lastAttackTime = al_get_time();}

	//Returns true if Entity has a target and the target is within the
	//	Entity's attackRange
	//else false
	bool inRangeOfTarget();

	//Returns the Entity's path. Created by AStar. SEE: AStar.h, PathingThread.h
	list<Point<int>>* getPath() const {return currentPath;}

	//Sets the Entity's path. 
	//	PARAMS:
	//list<Point<int>>* path: Created by AStar. SEE: AStar.h, PathingThread.h
	void setPath(list<Point<int>>* path);

	//Returns a pointer to AStar. SEE: AStar.h
	AStar* getAStar() {return aStar;}

	//Sets AStar, if not set during construction.
	void setAStar(AStar* astar) {aStar = astar;}

	//Returns the END goal of the Entity.
	//Return is the mapArray INDEXs
	Point<int> getGoal() const {return goal;}

	//Sets the goal of the Entity. Adds the new goal to AStar to find a path.
	//	PARAMS:
	//Point<int> goal: mapArray index location
	void setGoal(Point<int> goal);

	//Removes the goal of the Entity
	void removeGoal() {goal = Point<int>(-1, -1);}

	//Return false if goal.x or goal.y is less than 0.
	bool hasGoal() {if(goal.x < 0 || goal.y < 0) return false; else return true;}

	//Returns true if current location is == goal OR the current goal is (-1, -1)
	//	else return false	SEE: removeGoal()
	bool reachedGoal();

	//Returns the Entity's current Destination. NOT THE GOAL, but the
	//	Entity's next point to move to.
	//Returned Point is of mapArray index
	Point<int> getCurrentDestination() const {return currentDestination;}

	//Sets the Entity's current destination to passed dest.
	//	Example use:
	//	...
	//	setCurrentDestination(getPath()->front);
	//	getPath()->pop_front();
	//	...
	void setCurrentDestination(Point<int> dest) {currentDestination = dest;}

	//Sets the Entity's current movement direction. Used for displaying bitmaps.
	//	PARAMS:
	//Point<float> vector: A vector of the direction the Entity is going.
	void setDirection(Point<float> vector);

	//Sets that the Entity is blocked, AKA can't move to next destination for any reason.
	void setBlocked();

	//Sets that the Entity is not blocked. AKA whatever blocked it before, no longer blocks it now
	void setNotBlocked() {blockedTime = -1; firstBlockedTime = -1;}

	//Returns true if the Entity is blocked
	bool isBlocked() {return firstBlockedTime != -1;}

	//Updates the Entities path. If the entity is blocked for too long this will
	//	add the same Goal to AStar and attempt to go around the obstacle.
	void updatePath();

	//Returns true if the Entity is with a tile, not between two.
	//LIKE THIS:	---
	//Entity = 0	|0|
	//				---
	bool hasArrived() const {return arrived;}

	//Sets the the Entity has Arrived. SEE: hasArrived() for more info.
	void setArrived(bool t) {arrived = t;}

	//SEE: Doohickey.h
	virtual void draw(Point<float> cameraPos) = 0;

	//SEE: Doohickey.h
	virtual void update() = 0;

	//Used to delete Entity Images. Since the images are Static we shouldn't
	//	delete them when deleting a single Entity.
	//Used when closing the program.
	virtual void deleteImages() = 0;

	~Entity();
};

#endif